###########################################################################
#	$Id: Archive.p 7 2007-03-17 09:23:38Z beave $
###########################################################################

@CLASS
Archive


@auto[][sScriptPath]
$sScriptPath[/../data/scripts]

^if($bLib:PLATFORM eq 'win'){
	$SCRIPT_PATH[${sScriptPath}/archive.bat]
}{
	$SCRIPT_PATH[${sScriptPath}/archive.sh]
}

$ARCHIVER[]
$COMPRESSOR[]
#end @auto[]



###########################################################################
#	Options:
#		$.SCRIPT_PATH[string]
#		$.DEBUG_OBJECT[object]
###########################################################################
@init[hshParams][hParams]
$hParams[^hash::create[$hshParams]]

^if(def $hParams.SCRIPT_PATH){
	$SCRIPT_PATH[$hParams.SCRIPT_PATH]
}

$result[]
#end @init[]



###########################################################################
#	Detect file programms
###########################################################################
@detectProgramms[strFile]
# cleaning variables
$ARCHIVER[]
$COMPRESSOR[]

^switch[^file:justext[$strFile]]{
	^case[gz]{
		$COMPRESSOR[gzip]
	}
	^case[bz2]{
		$COMPRESSOR[bzip2]
	}
	^case[tgz]{
		$ARCHIVER[tar]
		$COMPRESSOR[gzip]
	}
	^case[zip]{
		$ARCHIVER[zip]
		$COMPRESSOR[$ARCHIVER]
	}
	^case[rar]{
		$ARCHIVER[rar]
		$COMPRESSOR[$ARCHIVER]
	}
}

^strFile.match[^^[\w:_\\/.]+\.tar\.(gz|bz2)^$][gi]{
	$ARCHIVER[tar]
}

^if(!def $ARCHIVER || !def $COMPRESSOR){
	^throw[Archive.file.type;^$ARCHIVER|^$COMPRESSOR;unknown file type]
}

$result[]
#end @detectProgramms[]



###########################################################################
#	Print home directory
#
#	Result: string
###########################################################################
@printHomeDir[strFile]
$result[^file:dirname[^file:fullpath[$strFile]]]
#end @printHomeDir[]



###########################################################################
#	Create archive
#
#	Parameters:
#		2. altSources[string|table]
###########################################################################
@create[strFile;altSources;strArchiver;strCompressor][sFile;sCompressor;tHomeContent;tRootContent;fCreate;iPos]
^if(!def $strFile){
	^throw[Archive.spec;^$strFile;param not specified]
}
^if(!def $altSources){
	^throw[Archive.spec;^$altSources;param not specified]
}

^if(def $strArchive || def $strCompressor){
	$ARCHIVER[$strArchiver]
	$COMPRESSOR[$strCompressor]
}{
	^self.detectProgramms[$strFile]
}

^if(-f $strFile){
	^file:delete[$strFile]
}

$sFile[^strFile.trim[]]

^if($ARCHIVER eq 'tar' && def $COMPRESSOR){
	$sCompressor[$COMPRESSOR]
	$COMPRESSOR[]

	$sFile[^file:justname[$sFile]]
}

^if($altSources is 'string'){
	^if(^altSources.left(1) eq '/'){
		$fCreate[^self._add[$sFile;^altSources.mid(1;^altSources.length[]);$request:document-root]]
	}{
		$fCreate[^self._add[$sFile;$altSources]]
	}
}{

	$tHomeContent[^altSources.select(^altSources.path.left(1) ne '/')]
	$tRootContent[^altSources.select(^altSources.path.left(1) eq '/')]

	^if($tHomeContent){
		$fCreate[^self._add[$sFile;^tHomeContent.menu{$tHomeContent.path}[^#20]]]
	}

	^if($tRootContent){
		$fCreate[^self._add[$sFile;^tRootContent.menu{^tRootContent.path.mid(1;^tRootContent.path.length[])}[^#20];$request:document-root]]
	}


	^if($ARCHIVER eq 'tar' && def $sCompressor){
		$ARCHIVER[]
		$COMPRESSOR[$sCompressor]
		
		$fCreate[^self._add[$sFile]]
		
		^if(-f $sFile){
			^file:delete[$sFile]
		}
	}

}

^if(! -f $strFile){
	^throw[Archive.file.create;$strFile;could not create file]
}

$result[]
#end @create[]



@_add[strFile;strSources;strHomeDir]
$result[^file::exec[$SCRIPT_PATH][
	$.CGI_HOME[^if(def $strHomeDir){$strHomeDir}{^bLib:preparePath[^self.printHomeDir[$strFile];$.full_path(true)]}]
	$.CGI_ARCHIVER[$ARCHIVER]
	$.CGI_COMPRESSOR[$COMPRESSOR]
][add;^bLib:preparePath[$strFile;$.full_path(true)];$strSources]]

^if($fCreate.status || def $fCreate.stderr){
	^self.parseErrors[$fCreate.stderr]
}
#end @_add[]



###########################################################################
#	Extract archive (to directory)
###########################################################################
@extract[strFile;strDirTo;strArchiver;strCompressor][sArchivePath;sExtractTo;fExtract]
^if(!def $strFile){
	^throw[Archive.spec;^$strFile;param not specified]
}
^if(!-f $strFile){
	^throw[Archive.file.missing;$strFile;file not found]
}

^if(def $strArchive || def $strCompressor){
	$ARCHIVER[$strArchiver]
	$COMPRESSOR[$strCompressor]
}{
	^self.detectProgramms[$strFile]
}

$sArchivePath[^bLib:preparePath[$strFile;$.full_path(true)]]
$sExtractTo[^bLib:preparePath[$strDirTo;$.full_path(true)]]

$fExtract[^file::exec[$SCRIPT_PATH][
	$.CGI_HOME[^bLib:preparePath[^self.printHomeDir[$strFile];$.full_path(true)]]
	$.CGI_ARCHIVER[$ARCHIVER]
	$.CGI_COMPRESSOR[$COMPRESSOR]
][extract;$sArchivePath;$sExtractTo]]

^if($fExtract.status || def $fExtract.stderr){
	^self.parseErrors[$fExtract.stderr]
}

$result[]
#end @extract[]



###########################################################################
#	Get archive content
#
#	Result: table
###########################################################################
@list[strFile;strArchiver;strCompressor][sArchivePath;fList]
^if(!def $strFile){
	^throw[Archive.list.spec;^$strFile;param not specified]
}

^if(def $strArchive || def $strCompressor){
	$ARCHIVER[$strArchiver]
	$COMPRESSOR[$strCompressor]
}{
	^self.detectProgramms[$strFile]
}

$result[^table::create{path}]

$sArchivePath[^bLib:preparePath[$strFile;$.full_path(true)]]

$fList[^file::exec[$SCRIPT_PATH][
	$.CGI_HOME[^bLib:preparePath[^self.printHomeDir[$strFile];$.full_path(true)]]
	$.CGI_ARCHIVER[$ARCHIVER]
	$.CGI_COMPRESSOR[$COMPRESSOR]
][list;$sArchivePath]]

^switch[$ARCHIVER]{
	^case[tar]{
		$result[^self.parseListTar[$fList.text]]
	}
	^case[rar]{
		$result[^self.parseListRar[$fList.text]]
	}
	^case[zip]{
		$result[^self.parseListZip[$fList.text]]
	}
	^case[DEFAULT]{
		^throw[Archive.unknown;^$ARCHIVER;unknown archiver]
	}
}
#end @list[]



@parseListTar[strBody]
$result[^table::create{path	size	dt	rights	user	group}]

^strBody.match[
	([rw\-]+)
	\s
	(\w+)/(\w+)
	\s+
	(\d+)
	\s
	(\d+\-\d+\-\d+)
	\s
	(\d+\:\d+\:\d+)
	\s
	([\w\.\-/_]+)
][gix]{
	^result.append{$match.7	$match.4	$match.5 $match.6	$match.1	$match.2	$match.3}
}
#end @parseListTar[]



@parseListZip[strBody]
$result[^table::create{path	size	dt}]

^strBody.match[
	\s+
	(\d+)
	\s+
	(\d+\-\d+\-\d+)
	\s
	(\d+\:\d+)
	\s+
	([\w\.\-/_]+)
][gix]{
	^result.append{$match.4	$match.1	$match.2 $match.3}
}
#end @parseListZip[]



@parseListRar[strBody]
$result[^table::create{path	size	dt	rights	packed	ratio	crc	method	version}]

^strBody.match[
	\s
	([\w\.\-/_]+)
	\s+
	(\d+)
	\s+
	(\d+)
	\s+
	(\d+%)
	\s
	(\d+\-\d+\-\d+)
	\s
	(\d+\:\d+)
	\s
	([rw\-]+)
	\s
	(\w+)
	\s
	(\w+)
	\s
	([\d\.]+)
][gix]{
	^result.append{$match.1	$match.2	$match.5 $match.6	$match.7	$match.3	$match.4	$match.8	$match.9	$match.10}
}
#end @parseListRar[]



@parseErrors[strErrors]
^strErrors.match[
	(zip)\s
	[\w:\\/\s]+
	No\ssuch\sfile\sor\sdirectory
][gix]{
	^throw[Archive.access;bb;permission denied]
}

^strErrors.match[
	(?:
		tar:\s
		([\w\.\-/_]+):\s
		Cannot\sstat:\s
		No\ssuch\sfile\sor\sdirectory
	|
		zip\swarning:\s
		name\snot\smatched:\s
		([\w\.\-/_]+)
	|
		Cannot\sopen\s
		([\w\.\-/_]+)\n
		No\ssuch\sfile\sor\sdirectory
	)
][gix]{
	^throw[Archive.search;${match.1}${match.2}${match.3};file or directory not found]
}

$result[]
#end @parseErrors[]
